// Copyright 2009 Vladimir Solomenchuk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package net.aramzamzam.tapestry.judo.demo.components;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import net.aramzamzam.tapestry.judo.services.Require;
import net.aramzamzam.tapestry.judo.services.RequireResource;
import net.aramzamzam.tapestry.judo.services.RequireResources;
import net.aramzamzam.tapestry.judo.services.RequireResource.ResourceType;

import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.StreamResponse;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.internal.services.ContextResource;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.internal.util.ClasspathResource;
import org.apache.tapestry5.runtime.Component;
import org.apache.tapestry5.services.ApplicationGlobals;
import org.apache.tapestry5.services.ComponentClassResolver;
import org.apache.tapestry5.services.Response;


@Require({"dojox.highlight","dojox.highlight.languages.html","dojox.highlight.languages.javascript"})
@RequireResources({
	@RequireResource(module="dojox",path="highlight/resources/highlight.css", resourceType=ResourceType.CSS),
	@RequireResource(module="dijit",path="themes/soria/soria.css", resourceType=ResourceType.CSS)
})
public class Layout {
	@Inject
	private ComponentClassResolver resolver;
	
	@SuppressWarnings("unchecked")
	@Property
	private Class page;
	
	@Inject
	private ComponentResources componentResources;
	
	@Inject
	private Messages messages;
	
	@Inject
	private ApplicationGlobals globals;
	
	public String getTitle()
	{
		Component p = componentResources.getPage();
		return messages.get(resolver.resolvePageClassNameToPageName(p.getClass().getCanonicalName()));
	}
	
	@SuppressWarnings("unchecked")
	public Class[] getPages() throws ClassNotFoundException {
		Component p = componentResources.getPage();
		return getClasses(p.getClass().getPackage().getName());
	}

	public String getPageName()
	{
		if (page==null)
			return null;
		return resolver.resolvePageClassNameToPageName(page.getCanonicalName());
	}
	
	public String getMenuPageName()
	{
		return messages.get(getPageName());
	}
	
	@SuppressWarnings("unchecked")
	private static Class[] getClasses(String pckgname)
			throws ClassNotFoundException {
		List<Class> classes = new ArrayList<Class>();
		// Get a File object for the package
		File directory = null;
		try {
			ClassLoader cld = Thread.currentThread().getContextClassLoader();
			if (cld == null) {
				throw new ClassNotFoundException("Can't get class loader.");
			}
			String path =  pckgname.replace('.', '/');
			URL resource = cld.getResource(path);
			if (resource == null) {
				path+="/";
				resource = cld.getResource(path);
				if (resource == null)
					throw new ClassNotFoundException("No resource for " + path);
			}
			directory = new File(resource.getFile());
		} catch (NullPointerException x) {
			throw new ClassNotFoundException(pckgname + " (" + directory
					+ ") does not appear to be a valid package");
		}
		if (directory.exists()) {
			// Get the list of the files contained in the package
			String[] files = directory.list();
			for (int i = 0; i < files.length; i++) {
				// we are only interested in .class files
				if (files[i].endsWith(".class")) {
					// removes the .class extension
					classes.add(Class.forName(pckgname + '.'
							+ files[i].substring(0, files[i].length() - 6)));
				}
			}
		} else {
			throw new ClassNotFoundException(pckgname
					+ " does not appear to be a valid package");
		}
		Class[] classesA = new Class[classes.size()];
		Collections.sort(classes, new Comparator<Class>(){

			@Override
			public int compare(Class o1, Class o2) {
				return o1.getCanonicalName().compareTo(o2.getCanonicalName());
			}
			
		});
		classes.toArray(classesA);
		return classesA;
	}

	private String resource2String(Resource resource) throws IOException
	{
		String result;
		if (resource.exists())
		{
			InputStream is=null;
			try
			{
				is = resource.openStream();
				
				final char[] buffer = new char[0x10000];
				StringBuilder out = new StringBuilder();
				Reader in = new InputStreamReader(is, "UTF-8");
				int read;
				do 
				{
				  read = in.read(buffer, 0, buffer.length);
				  if (read>0)
				    out.append(buffer, 0, read);
				 }
				while (read>=0);
				result=out.toString();
			}
			finally
			{
				if (is!=null) is.close();
			}
		}
		else
			result=resource.getPath()+" not found";
		return result;
	}
	
	Object onActionFromTml() throws ClassNotFoundException
	{
		final String pname=resolver.resolvePageClassNameToPageName(componentResources.getPage().getClass().getCanonicalName());
		return new StreamResponse() {
			
			@Override
			public void prepareResponse(Response response) {
			}
			
			@Override
			public InputStream getStream() throws IOException {
				ContextResource resource = new ContextResource(globals.getContext(), pname+".tml");
				String result=resource2String(resource);
				result = "<pre><code class=\"html\">"+result.replaceAll(":", "---").replaceAll("<", "&lt;").replaceAll(">", "&gt;")+"</code></pre>";
				return new ByteArrayInputStream( result.getBytes( "utf-8" ) );

			}
			
			@Override
			public String getContentType() {
				return "text/html, charset=utf-8";
			}
		};
	}
	
	Object onActionFromJava() throws ClassNotFoundException
	{
		final String pname=componentResources.getPage().getClass().getCanonicalName();
		return new StreamResponse() {
			
			@Override
			public void prepareResponse(Response response) {
			}
			
			@Override
			public InputStream getStream() throws IOException {
				String path=pname.replace('.', '/')+".java";
				ClasspathResource resource = new ClasspathResource(path);
				String result=resource2String(resource);
				result = "<pre><code class=\"javascript\">"+result+"</code></pre>";
				return new ByteArrayInputStream( result.getBytes( "utf-8" ) );

			}
			
			@Override
			public String getContentType() {
				return "text/html, charset=utf-8";
			}
		};
	}

}
